home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / workbench+shell / q-z / wbtitle / source / wbtitle.c < prev    next >
C/C++ Source or Header  |  1978-06-29  |  12KB  |  507 lines

  1. /*
  2.  * WBTitle
  3.  *
  4.  * Version 1.0
  5.  *
  6.  * Public Domain Software
  7.  *
  8.  * This program replaces the Amiga's Workbench title bar so that it
  9.  * shows all types of memory available: Chip, Public, VM, and Retina.
  10.  */
  11.  
  12. #include <string.h>
  13. #include <ctype.h>
  14.  
  15. #include <exec/types.h>
  16. #include <exec/memory.h>
  17. #include <intuition/intuition.h>
  18. #include <dos/dos.h>
  19.  
  20. #include <proto/exec.h>
  21. #include <proto/intuition.h>
  22. #include <proto/dos.h>
  23. #include <proto/retina.h>
  24. #include <proto/vmm.h>
  25.  
  26. #include <clib/alib_protos.h>
  27.  
  28. // The SetWindowTitles function offset
  29. #define SWTOffset -276
  30.  
  31. enum {
  32.     JMPINSTR = 0x4ef9
  33. };
  34.  
  35. typedef struct JmpEntry {
  36.     UWORD Instr;
  37.     APTR Func;
  38. } JmpEntry;
  39.  
  40. static BOOL Replace(void);
  41. static void Restore(void);
  42. static void __asm new_SetWindowTitles(register __a0 struct Window *,
  43.                                 register __a1 UBYTE *, register __a2 UBYTE *,
  44.                                 register __a6 struct Library *);
  45. static void NumberToString(ULONG number);
  46. static void format_number(ULONG number);
  47. static void no_lead_triple(ULONG number);
  48. static void lead_triple(ULONG number);
  49.  
  50. // Global variables
  51. struct RetinaBase *RetinaBase;
  52. struct Library *VMMBase;
  53.  
  54. // Local variables
  55. static char verstring[] = "$VER: WBTitle 1.0 " __AMIGADATE__;
  56. static char port_name[] = "WBTitle";
  57.  
  58. static void __asm (*old_SetWindowTitles)(register __a0 struct Window *,
  59.                                     register __a1 UBYTE *,
  60.                                     register __a2 UBYTE *,
  61.                                     register __a6 struct Library *);
  62. static JmpEntry *SWTEntry;
  63. static char *chip_str, *fast_str, *public_str, *total_str, *virtual_str;
  64. static char *retina_str, *memorder_str, *prefix_str, *suffix_str, *labels_str;
  65. static char *comma_str, *mem_str, *last_str, *buff_ptr;
  66. static char num_buf[14], comma;
  67. static int units, num_size, mem_str_len, prefix_str_len;
  68. static BOOL sep1000, labels_after;
  69.  
  70. /*
  71.  * The main method for replacing an Amiga OS function as safe as
  72.  * possible is to place the function with a jump table that is
  73.  * allocated.  While the function is replaced, the jump table simply
  74.  * jumps to my routine:
  75.  *
  76.  * jmp  _new_SetWindowTitles
  77.  *
  78.  * When the user asks the program to quit, we can't simply put the
  79.  * pointer back that SetFunction() gives us since someone else might
  80.  * have replaced the function.  So, we first see if the pointer we
  81.  * get back points to the out jump table.  If so, then we _can_ put
  82.  * the pointer back like normal (no one has replaced the function
  83.  * while we has it replaced).  But if the pointer isn't mine, then
  84.  * we have to replace the jump table function pointer to the old
  85.  * function pointer:
  86.  *
  87.  * jmp  _old_SetWindowTitles
  88.  *
  89.  * Finally, we only deallocate the jump table _if_ we did not have
  90.  * to change the jump table.
  91.  */
  92.  
  93. main(int argc, char *argv[])
  94. {
  95.     struct MsgPort *port;
  96.  
  97.     // FindPort() Forbid()
  98.     Forbid();
  99.  
  100.     port = FindPort(port_name);
  101.     if (port) {
  102.         struct MsgPort *reply_port;
  103.  
  104.         // Create a reply port
  105.         reply_port = CreateMsgPort();
  106.         if (reply_port) {
  107.             struct Message msg;
  108.  
  109.             // Set fields in message structure
  110.             msg.mn_ReplyPort = reply_port;
  111.             msg.mn_Length = sizeof(struct Message);
  112.  
  113.             // Send the message
  114.             PutMsg(port, &msg);
  115.  
  116.             // Finished with port, so stop FindPort() Forbid()
  117.             Permit();
  118.  
  119.             // Wait for a reply
  120.             do {
  121.                 WaitPort(reply_port);
  122.             } while (GetMsg(reply_port) == NULL);
  123.  
  124.             // Clear and Delete reply_port Forbid()
  125.             Forbid();
  126.  
  127.             // Clear any messages
  128.             while (GetMsg(reply_port));
  129.  
  130.             // Delete the reply port
  131.             DeleteMsgPort(reply_port);
  132.  
  133.             // Clear and Delete reply_port stop Forbid()
  134.             Permit();
  135.         } else {
  136.             // Finished with port, so stop FindPort() Forbid()
  137.             Permit();
  138.         }
  139.     } else if (port = CreateMsgPort()) {
  140.         struct Message *msg;
  141.         char **ttypes;
  142.  
  143.         // Finished with port, so stop FindPort() Forbid()
  144.         Permit();
  145.  
  146.         // Setup quitting port
  147.         port->mp_Node.ln_Name = port_name;
  148.         port->mp_Node.ln_Pri = -120;
  149.  
  150.         // Add quitting port to public list
  151.         AddPort(port);
  152.  
  153.         // Open the Retina library
  154.         RetinaBase = (struct RetinaBase *)OpenLibrary("retina.library", 0);
  155.  
  156.         // Check on VMM; look for port, and alloc signal
  157.         if (FindPort("VMM_Port")) {
  158.             VMMBase = OpenLibrary("vmm.library", 0);
  159.         }
  160.  
  161.         // Setup to read some arguements
  162.         ttypes = ArgArrayInit(argc, argv);
  163.  
  164.         // Read some arguments
  165.         prefix_str = ArgString(ttypes, "PREFIX", "Amiga Workbench  ");
  166.         suffix_str = ArgString(ttypes, "SUFFIX", "");
  167.         labels_str = ArgString(ttypes, "LABELS", "AFTER");
  168.  
  169.         chip_str = ArgString(ttypes, "CHIP", " Chip  ");
  170.         fast_str = ArgString(ttypes, "FAST", " Fast  ");
  171.         public_str = ArgString(ttypes, "PUBLIC", " Public  ");
  172.         total_str = ArgString(ttypes, "TOTAL", " Total  ");
  173.         virtual_str = ArgString(ttypes, "VIRTUAL", " Virtual  ");
  174.         retina_str = ArgString(ttypes, "RETINA", " Retina  ");
  175.  
  176.         memorder_str = ArgString(ttypes, "MEMORDER", "CVPR");
  177.         sep1000 = (ArgString(ttypes, "THOUSANDSEP", NULL) != NULL);
  178.         units = ArgInt(ttypes, "UNITS", 1);
  179.         comma_str = ArgString(ttypes, "SEPERATOR", NULL);
  180.         if (comma_str && comma_str[0]) {
  181.             comma = comma_str[0];
  182.         } else {
  183.             comma = ',';
  184.         }
  185.  
  186.         labels_after = (stricmp(labels_str, "BEFORE") != 0);
  187.         if (units < 0) {
  188.             units = 1;
  189.         }
  190.  
  191.         // Compute the size of numbers
  192.         {
  193.             ULONG maxnum = 0xffffffff;
  194.  
  195.             // Compute the number of digits
  196.             maxnum /= units;
  197.             while (maxnum) {
  198.                 maxnum /= 10;
  199.                 num_size++;
  200.             }
  201.  
  202.             // Compute the number of commas
  203.             if (sep1000) {
  204.                 int com = num_size;
  205.                 while (com > 3) {
  206.                     num_size++;
  207.                     com -= 3;
  208.                 }
  209.             }
  210.         }
  211.  
  212.         // Compute the size of the mem string
  213.         {
  214.             ULONG i = 0;
  215.             char ch;
  216.  
  217.             // Add in the prefix string size
  218.             mem_str_len = prefix_str_len = strlen(prefix_str);
  219.  
  220.             // Add in the memory parts
  221.             while (ch = toupper(memorder_str[i])) {
  222.                 switch (ch) {
  223.                     case 'C':
  224.                         mem_str_len += strlen(chip_str) + num_size;
  225.                         break;
  226.                     case 'F':
  227.                         mem_str_len += strlen(fast_str) + num_size;
  228.                         break;
  229.                     case 'P':
  230.                         mem_str_len += strlen(public_str) + num_size;
  231.                         break;
  232.                     case 'T':
  233.                         mem_str_len += strlen(total_str) + num_size;
  234.                         break;
  235.                     case 'V':
  236.                         if (VMMBase) {
  237.                             mem_str_len += strlen(virtual_str) + num_size;
  238.                         }
  239.                         break;
  240.                     case 'R':
  241.                         if (RetinaBase) {
  242.                             mem_str_len += strlen(retina_str) + num_size;
  243.                         }
  244.                         break;
  245.                 }
  246.                 i++;
  247.             }
  248.  
  249.             // Add in the suffix string size
  250.             mem_str_len += strlen(suffix_str);
  251.         }
  252.  
  253.         if (mem_str_len > 0) {
  254.             // Allocate the memory
  255.             mem_str = AllocMem(mem_str_len + 1, MEMF_PUBLIC);
  256.             if (mem_str) {
  257.                 strcpy(mem_str, prefix_str);
  258.                 last_str = &mem_str[prefix_str_len];
  259.  
  260.                 // Attempt to replace function
  261.                 if (Replace()) {
  262.                     // Wait for someone to signal me to quit
  263.                     do {
  264.                         WaitPort(port);
  265.                         msg = GetMsg(port);
  266.                     } while (msg == NULL);
  267.                     ReplyMsg(msg);
  268.  
  269.                     // Restore function
  270.                     Restore();
  271.                 }
  272.                 FreeMem(mem_str, mem_str_len + 1);
  273.             }
  274.         }
  275.  
  276.         // Cleanup from reading arguments
  277.         ArgArrayDone();
  278.  
  279.         // Remove port from public access
  280.         RemPort(port);
  281.  
  282.         // Clear and Delete port Forbid()
  283.         Forbid();
  284.  
  285.         // Clear the port of messages
  286.         while (msg = GetMsg(port)) {
  287.             ReplyMsg(msg);
  288.         }
  289.  
  290.         // Closedown quitting port
  291.         DeleteMsgPort(port);
  292.  
  293.         // Clear and Delete port stop Forbid()
  294.         Permit();
  295.     }
  296. }
  297.  
  298. static BOOL Replace(void)
  299. {
  300.     // Allocate the jump table
  301.     SWTEntry = AllocMem(sizeof(JmpEntry), 0);
  302.     if (SWTEntry) {
  303.         // Replacement Forbid()
  304.         Forbid();
  305.  
  306.         // Replace the function with pointer to jump table
  307.         old_SetWindowTitles = SetFunction((struct Library *)IntuitionBase,
  308.                                             SWTOffset, (ULONG (*)())SWTEntry);
  309.  
  310.         // Setup the jump table
  311.         SWTEntry->Instr = JMPINSTR;
  312.         SWTEntry->Func = new_SetWindowTitles;
  313.  
  314.         // Clear the cpu's cache so the execution cache is valid
  315.         CacheClearU();
  316.  
  317.         // Stop the replacement Forbid()
  318.         Permit();
  319.  
  320.         return TRUE;
  321.     } else {
  322.         return FALSE;
  323.     }
  324. }
  325.  
  326. static void Restore(void)
  327. {
  328.     BOOL my_table;
  329.     ULONG (*func)();
  330.  
  331.     // Fix back Forbid()
  332.     Forbid();
  333.  
  334.     // Put old pointer back and get current pointer at same time
  335.     func = SetFunction((struct Library *)IntuitionBase, SWTOffset,
  336.                             (ULONG (*)())old_SetWindowTitles);
  337.  
  338.     // Check to see if the pointer we get back is ours
  339.     if ((JmpEntry *)func != SWTEntry) {
  340.         // If not, leave jump table in place
  341.         my_table = FALSE;
  342.         SetFunction((struct Library *)IntuitionBase, SWTOffset,
  343.                     func);
  344.         SWTEntry->Func = old_SetWindowTitles;
  345.     } else {
  346.         // If so, free the jump table
  347.         my_table = TRUE;
  348.         FreeMem(SWTEntry, sizeof(JmpEntry));
  349.     }
  350.  
  351.     // Clear the cpu's cache so the execution cache is valid
  352.     CacheClearU();
  353.  
  354.     // Stop fix back Forbid()
  355.     Permit();
  356.  
  357.     // Let the user know if the jump table couldn't be freed
  358.     if (!my_table) {
  359.         DisplayBeep(NULL);
  360.     }
  361.  
  362.     // Wait 5 seconds to try and guarantee that all tasks have
  363.     // finished executing inside my replacement function before
  364.     // quitting.  There's no real way to guarantee, though.
  365.     Delay(250);
  366. }
  367.  
  368. static void __saveds __asm new_SetWindowTitles(
  369.                             register __a0 struct Window *window,
  370.                             register __a1 UBYTE *win_title,
  371.                             register __a2 UBYTE *scr_title,
  372.                             register __a6 struct Library *lib)
  373. {
  374.     if (scr_title && (scr_title != (UBYTE *)0xffffffff) &&
  375.             (*scr_title == 'A') && strstr(scr_title, "graphics mem")) {
  376.         ULONG i = 0;
  377.         char ch;
  378.  
  379.         // Set last_str to nothing
  380.         *last_str = 0;
  381.  
  382.         // Add in the memory parts
  383.         while (ch = toupper(memorder_str[i])) {
  384.             switch (ch) {
  385.                 case 'C':
  386.                     if (!labels_after) {
  387.                         strcat(last_str, chip_str);
  388.                     }
  389.                     NumberToString(AvailMem(MEMF_CHIP));
  390.                     strcat(last_str, num_buf);
  391.                     if (labels_after) {
  392.                         strcat(last_str, chip_str);
  393.                     }
  394.                     break;
  395.                 case 'F':
  396.                     if (!labels_after) {
  397.                         strcat(last_str, fast_str);
  398.                     }
  399.                     NumberToString(AvailMem(MEMF_FAST));
  400.                     strcat(last_str, num_buf);
  401.                     if (labels_after) {
  402.                         strcat(last_str, fast_str);
  403.                     }
  404.                     break;
  405.                 case 'P':
  406.                     if (!labels_after) {
  407.                         strcat(last_str, public_str);
  408.                     }
  409.                     NumberToString(AvailMem(MEMF_PUBLIC));
  410.                     strcat(last_str, num_buf);
  411.                     if (labels_after) {
  412.                         strcat(last_str, public_str);
  413.                     }
  414.                     break;
  415.                 case 'T':
  416.                     if (!labels_after) {
  417.                         strcat(last_str, total_str);
  418.                     }
  419.                     NumberToString(AvailMem(0));
  420.                     strcat(last_str, num_buf);
  421.                     if (labels_after) {
  422.                         strcat(last_str, total_str);
  423.                     }
  424.                     break;
  425.                 case 'V':
  426.                     if (VMMBase) {
  427.                         if (!labels_after) {
  428.                             strcat(last_str, virtual_str);
  429.                         }
  430.                         NumberToString(AvailVMem(0));
  431.                         strcat(last_str, num_buf);
  432.                         if (labels_after) {
  433.                             strcat(last_str, virtual_str);
  434.                         }
  435.                     }
  436.                     break;
  437.                 case 'R':
  438.                     if (RetinaBase) {
  439.                         if (!labels_after) {
  440.                             strcat(last_str, retina_str);
  441.                         }
  442.                         NumberToString(Retina_AvailMem(0));
  443.                         strcat(last_str, num_buf);
  444.                         if (labels_after) {
  445.                             strcat(last_str, retina_str);
  446.                         }
  447.                     }
  448.                     break;
  449.             }
  450.             i++;
  451.         }
  452.         strcat(last_str, suffix_str);
  453.         old_SetWindowTitles(window, win_title, mem_str, lib);
  454.     } else {
  455.         old_SetWindowTitles(window, win_title, scr_title, lib);
  456.     }
  457. }
  458.  
  459. /*
  460.  * Convert the number to a string in the format the user specified.
  461.  * The string generated is 0 terminated.
  462.  *
  463.  * Uses global variables: buff_ptr, num_buff
  464.  */
  465.  
  466. static void NumberToString(ULONG number)
  467. {
  468.     number /= units;
  469.     if (sep1000) {
  470.         buff_ptr = num_buf;
  471.         format_number(number);
  472.         *buff_ptr = 0;
  473.     } else {
  474.         stcul_d(num_buf, number);
  475.     }
  476. }
  477.  
  478. static void format_number(ULONG number)
  479. {
  480.     if (number > 1000) {
  481.         format_number(number / 1000);
  482.         lead_triple(number % 1000);
  483.     } else {
  484.         no_lead_triple(number);
  485.     }
  486. }
  487.  
  488. static void no_lead_triple(ULONG number)
  489. {
  490.     if (number > 10) {
  491.         no_lead_triple(number / 10);
  492.         *buff_ptr++ = ((number % 10) | 0x30);
  493.     } else {
  494.         *buff_ptr++ = (number | 0x30);
  495.     }
  496. }
  497.  
  498. static void lead_triple(ULONG number)
  499. {
  500.     *buff_ptr++ = comma;
  501.     *buff_ptr++ = ((number / 100) | 0x30);
  502.     number %= 100;
  503.     *buff_ptr++ = ((number / 10) | 0x30);
  504.     number %= 10;
  505.     *buff_ptr++ = (number | 0x30);
  506. }
  507.